import axios from "axios"
import router from "@/router"
import Vue from "vue"
import tokenRefresh from "./token-refresh"
import token from "./token"
import message from "./message"
// import JSONbig from "json-bigint"

let $vm = new Vue()
let isLock = true
let requests = []

function clearData() {
    isLock = true
    requests = []
    token.clear()
    gotoLogin()
}

function gotoLogin() {
    router.push({
        path: "/login",
        query: { redirect: router.fullPath },
    })
}

// 创建 axios 实例
let service = axios.create({
    baseUrl: process.env.NODE_ENV === "development" ? "/" : process.env.VUE_APP_URL,
    timeout: 10000, // 请求超时时间
    crossDomain: true, //设置cross跨域
    withCredentials: true, //设置cross跨域 并设置访问权限 允许跨域携带cookie信息
    // transformResponse: [
    //   function (data) {
    //     try {
    //       // 作用1：把json字符串转为js对象
    //       // 作用2：把里面的大数字做安全处理
    //       let tmp = JSONbig.parse(data)
    //       tmp.id = tmp.id.toString()
    //       return tmp
    //     } catch (e) {
    //       return data
    //     }
    //   },
    // ],
})

const axiosConf = (config) => {
    // Do something before request is sent
    //config.withCredentials = true // 允许携带token ,这个是解决跨域产生的相关问题
    config.timeout = 6000
        //config.headers["Content-Type"] = "application/x-www-form-urlencoded"
    config.headers["Content-Type"] = "application/json"
    config.headers["uuid"] = $vm.$token.getUUID() // 未有token则发送uuid
    if ($vm.$token.has()) {
        config.headers["token"] = $vm.$token.get() // 将token放到请求头发送给服务器
            // 这里经常搭配token使用，将token值配置到tokenkey中，将tokenkey放在请求头中
            // config.headers['accessToken'] = Token;
    }
    return config
}

// http request拦截器 添加一个请求拦截器
service.interceptors.request.use(
    (config) => {
        return axiosConf(config)
    },
    (error) => {
        return Promise.reject(error)
    }
)

service.interceptors.response.use(
    async(response) => {
        // 处理响应数据
        let code = Number(response.data.code)
        if (code != 401) {
            return response
        }

        if (!isLock) {
            // 正在刷新token，将返回一个未执行resolve的promise
            return new Promise((resolve) => {
                // 将resolve放进队列，用一个函数形式来保存，等token刷新后直接执行
                requests.push(() => {
                    resolve(service.request(axiosConf(response.config)))
                })
            })
        }

        let refreshTokenString = await $vm.$token.getRefreshToken()
        if (refreshTokenString == "") {
            clearData()
            return {
                code: -1,
                message: "token为空",
            }
        }

        isLock = false
        const resultfresh = await tokenRefresh()
        if (resultfresh * 1 !== 200) {
            clearData()
            return {
                code: -1,
                message: "登录超时，请您重新登录",
            }
        }

        //执行挂起进程
        requests.forEach((cb) => cb())
        requests = []
        isLock = true

        return await service.request(axiosConf(response.config))
    },
    (error) => {
        // 处理响应失败
        if (error && error.response && error.response.status) {
            let message_tmp = "服务器发生错误，请您稍后再试"
            switch (error.response.status) {
                case 403:
                    message_tmp = "无权限"
                    break
                case 404:
                    message_tmp = "网络请求不存在"
                    break
                case 500:
                    message_tmp = "哎呀~ (ಥ﹏ಥ)网络又开小差了,请您稍后刷新重试! "
                    break
            }
            if (
                Object.prototype.hasOwnProperty.call(error.response.data, "message") &&
                error.response.data.message
            ) {
                message_tmp = error.response.data.message
            }
            switch (error.response.status) {
                // 401: 未登录
                // 未登录则跳转登录页面，并携带当前页面的路径
                // 在登录成功后返回当前页面，这一步需要在登录页操作。
                case 401:
                    message.warning("页面超时，请您重新登录 [401]")
                    clearData()
                    break
                case 408:
                    message.warning("页面超时，请您重新登录 [408]")
                    clearData()
                    break
                default:
                    message.error(message_tmp + " [" + error.response.status + "]")
                    break
            }
            let data = error.response.data ? error.response.data : error.response
            return Promise.reject(data)
        }
        return Promise.reject(error)
    }
)

let tmpHosts = window.location.host
if (process.env.NODE_ENV === "development") {
    let tmpArr = process.env.VUE_APP_URL.split("//")
    if (tmpArr.length >= 1) {
        tmpArr = tmpArr[1].split("/")
        tmpHosts = tmpArr[0]
    }
}

// const VUE_APP_URL = process.env.VUE_APP_URL
const VUE_APP_URL_VERSION = process.env.VUE_APP_URL_VERSION
const prefixURL = VUE_APP_URL_VERSION ? "/" + VUE_APP_URL_VERSION : ""
const hosts = tmpHosts
const visitURL = window.location.protocol + "//" + hosts + prefixURL
const wsURL =
    (window.location.protocol == "https:" ? "wss://" : "ws://") +
    hosts +
    prefixURL

export default {
    PrefixURL: prefixURL,
    URL: visitURL,
    WSURL: wsURL,
    request(method, url, params) {
        url = this.PrefixURL + url

        let key = "timestamp"
        const value = new Date().getTime()
        switch (method.toUpperCase()) {
            case "GET":
                if (Object.prototype.toString.call(params) === "[object Object]") {
                    if (Object.prototype.hasOwnProperty.call(params, key)) {
                        key = "rnd" + value
                    }
                    params[key] = value
                    break
                }
                params = { timestamp: new Date().getTime() }
                break
            default:
                if (url.indexOf("?") === -1) {
                    url += "?" + key + "=" + value
                    break
                }
                url += "&" + key + "=" + value

                break
        }
        return new Promise((resolve, reject) => {
            service({
                    method: method,
                    url: url,
                    headers: {
                        "Content-type": "application/json; charset=utf-8",
                    },
                    data: params,
                })
                .then((res) => {
                    resolve(res.data)
                })
                .catch((err) => {
                    reject(err)
                })
        })
    },
    gettingFlag: {},
    gettingRequest: {},
    async get(url, params) {
        url = this.PrefixURL + url

        let tmpKeyString = url
        for (let k in params) {
            tmpKeyString += tmpKeyString == "" ? "?" : "&"
            tmpKeyString += k + "=" + params[k]
        }

        // 重复请求，存入阻塞队列
        if (
            Object.prototype.hasOwnProperty.call(this.gettingFlag, tmpKeyString) &&
            this.gettingFlag[tmpKeyString] == true
        ) {
            if (!Object.prototype.hasOwnProperty.call(this.gettingRequest, tmpKeyString)) {
                this.gettingRequest[tmpKeyString] = []
            }
            return new Promise((resolve) => {
                this.gettingRequest[tmpKeyString].push((res) => {
                    resolve(res)
                })
            })
        }

        this.gettingFlag[tmpKeyString] = true

        if (Object.prototype.toString.call(params) === "[object Object]") {
            let key = "timestamp"
            const value = new Date().getTime()
            if (Object.prototype.hasOwnProperty.call(params, key)) {
                key = "rnd" + value
            }
            params[key] = value
        } else {
            params = { timestamp: new Date().getTime() }
        }

        let response = await service
            .get(url, {
                params: params,
            })
            .then((res) => {
                return res.data
            })
            .catch((err) => {
                return Promise.reject(err)
            })

        if (
            Object.prototype.hasOwnProperty.call(this.gettingRequest, tmpKeyString)
        ) {
            this.gettingRequest[tmpKeyString].forEach((cb) => cb(response))
            this.gettingRequest[tmpKeyString] = []
        }

        this.gettingFlag[tmpKeyString] = false
        return response
    },
    patch(url, params) {
        return this.request("PATCH", url, params)
    },
    put(url, params) {
        return this.request("PUT", url, params)
    },
    delete(url, params) {
        return this.request("DELETE", url, params)
    },
    post(url, params) {
        return this.request("POST", url, params)
    },
}